/*
 * SoftwareSAR - 1.0
 */
package br.com.cpqd.ssar.utilitarias;

import java.awt.Color;
import java.util.Vector;

/**
 * Classe que Define uma Geometria
 * @author Rafael Buck, Igor
 * @version 1.3
 */
public class Geometria {

    private int identificador;
    private String nome;
    private AtributosGeometria atributos;
    private boolean visivel;
    private float visibilidade = 1.0f;
    private boolean solido;
    private Material material;
    // Parte de Dados Importante para o Gerador de Malha
    private Triangulo[] listaTriangulos;
    private float xMin,  xMax;
    private float yMin,  yMax;
    private float zMin,  zMax;
    private float rotX = 0.0f;
    private float rotY = 0.0f;
    private float rotZ = 0.0f;
    private float transX = 0.0f;
    private float transY = 0.0f;
    private float transZ = 0.0f;

    /**
     * Método Construtor
     */
    public Geometria() {
    }

    /**
     * Método Construtor Sobrecarregado (Importador STL)
     * @param identificador int
     * @param nome String
     * @param material Material
     * @param atributos AtributosGeometria
     * @param listaTriangulos Triangulo[]
     */
    public Geometria(int identificador, String nome, Material material, AtributosGeometria atributos, Triangulo[] listaTriangulos) {
        this.identificador = identificador;
        this.nome = nome;
        this.material = material;
        this.atributos = atributos;
        this.listaTriangulos = listaTriangulos;
    }

    public void transladaParaCentro() {
        atributos.referencial[0] = 0.0f;
        atributos.referencial[1] = 0.0f;
        atributos.referencial[2] = 0.0f;

    }

    public void transladaParaCentroCubo() {
        
        float[] firstPoint = new float[3];
        float[] secondPoint = new float[3];
        
        secondPoint[0] = atributos.getSecondPoint()[0] - atributos.getFirsPoint()[0];
        secondPoint[1] = atributos.getSecondPoint()[1] - atributos.getFirsPoint()[1];
        secondPoint[2] = atributos.getSecondPoint()[2] - atributos.getFirsPoint()[2];
        firstPoint[0] = 0.0f;
        firstPoint[1] = 0.0f;
        firstPoint[2] = 0.0f;
        
        atributos.setFirsPoint(firstPoint);
        atributos.setReferencial(firstPoint);
        atributos.setSecondPoint(secondPoint);
        

    }

    /**
     * Método Construtor Sobrecarregado (Gerenciador)
     * @param identificador
     * @param nome
     * @param atributos
     * @param visivel
     * @param solido
     * @param material
     * @param rotX
     * @param rotY
     * @param rotZ
     */
    public Geometria(int identificador, String nome, AtributosGeometria atributos, boolean visivel, boolean solido, Material material, float rotX, float rotY, float rotZ) {
        this.identificador = identificador;
        this.nome = nome;
        this.atributos = atributos;
        this.visivel = visivel;
        this.solido = solido;
        this.material = material;
        this.rotX = rotX;
        this.rotY = rotY;
        this.rotZ = rotZ;
    }

    /**
     * Get the value of listaTriangulos
     * @return the value of listaTriangulos
     */
    public Triangulo[] getListaTriangulos() {

        return listaTriangulos;
    }

    /**
     * Set the value of listaTriangulos
     * @param listaTriangulos new value of listaTriangulos
     */
    public void setListaTriangulos(Triangulo[] listaTriangulos) {
        this.listaTriangulos = null;
        this.listaTriangulos = listaTriangulos;
    }

    /**
     * Get the value of listaTriangulos at specified index
     * @param index
     * @return the value of listaTriangulos at specified index
     */
    public Triangulo getListaTriangulos(int index) {
        return this.listaTriangulos[index];
    }

    /**
     * Set the value of listaTriangulos at specified index.
     * @param index
     * @param newListaTriangulos new value of listaTriangulos at specified index
     */
    public void setListaTriangulos(int index, Triangulo newListaTriangulos) {
        this.listaTriangulos[index] = newListaTriangulos;
    }

    /**
     * Get the value of atributos
     * @return the value of atributos
     */
    public AtributosGeometria getAtributos() {
        return atributos;
    }

    /**
     * Set the value of atributos
     * @param atributos new value of atributos
     */
    public void setAtributos(AtributosGeometria atributos) {
        this.atributos = atributos;
       
    }

    /**
     * Get the value of material
     * @return the value of material
     */
    public Material getMaterial() {
        return material;
    }

    /**
     * Set the value of material
     * @param material new value of material
     */
    public void setMaterial(Material material) {
        this.material = material;
    }

    /**
     * Get the value of nome
     * @return the value of nome
     */
    public String getNome() {
        return nome;
    }

    /**
     * Set the value of nome
     * @param nome new value of nome
     */
    public void setNome(String nome) {
        this.nome = nome;
    }

    /**
     * Get the value of identificador
     * @return the value of identificador
     */
    public int getIdentificador() {
        return identificador;
    }

    /**
     * Set the value of identificador
     * @param identificador new value of identificador
     */
    public void setIdentificador(int identificador) {
        this.identificador = identificador;
    }

    public void setVisibilidade(float valor) {
        visibilidade = valor;
    }

    public float getVisibilidade() {
        return visibilidade;
    }

    public void rotacionarX(float rotX) {

        Vector rotacionados = new Vector();
        rotacionados.clear();

        float tempy,  tempz;

        /* Adiciona o primeiro triangulo (3 vértices) na lista de Rotacionados */
        rotacionados.add(this.listaTriangulos[0].getVertice(0));
        rotacionados.add(this.listaTriangulos[0].getVertice(1));
        rotacionados.add(this.listaTriangulos[0].getVertice(2));
        /* E também os rotaciona */ //VERTICE 1
        tempy = (float) (this.listaTriangulos[0].getVertice(0).getCoordenada(1) * Math.cos(Math.toRadians(rotX))) - (float) (this.listaTriangulos[0].getVertice(0).getCoordenada(2) * Math.sin(Math.toRadians(rotX)));
        tempz = (float) (this.listaTriangulos[0].getVertice(0).getCoordenada(1) * Math.sin(Math.toRadians(rotX))) + (float) (this.listaTriangulos[0].getVertice(0).getCoordenada(2) * Math.cos(Math.toRadians(rotX)));
        this.listaTriangulos[0].getVertice(0).setCoordenada(1, tempy);
        this.listaTriangulos[0].getVertice(0).setCoordenada(2, tempz);
        // VETICE 2
        tempy = (float) (this.listaTriangulos[0].getVertice(1).getCoordenada(1) * Math.cos(Math.toRadians(rotX))) - (float) (this.listaTriangulos[0].getVertice(1).getCoordenada(2) * Math.sin(Math.toRadians(rotX)));
        tempz = (float) (this.listaTriangulos[0].getVertice(1).getCoordenada(1) * Math.sin(Math.toRadians(rotX))) + (float) (this.listaTriangulos[0].getVertice(1).getCoordenada(2) * Math.cos(Math.toRadians(rotX)));
        this.listaTriangulos[0].getVertice(1).setCoordenada(1, tempy);
        this.listaTriangulos[0].getVertice(1).setCoordenada(2, tempz);
        // VERTICE 3 do Primeiro triangulo
        tempy = (float) (this.listaTriangulos[0].getVertice(2).getCoordenada(1) * Math.cos(Math.toRadians(rotX))) - (float) (this.listaTriangulos[0].getVertice(2).getCoordenada(2) * Math.sin(Math.toRadians(rotX)));
        tempz = (float) (this.listaTriangulos[0].getVertice(2).getCoordenada(1) * Math.sin(Math.toRadians(rotX))) + (float) (this.listaTriangulos[0].getVertice(2).getCoordenada(2) * Math.cos(Math.toRadians(rotX)));
        this.listaTriangulos[0].getVertice(2).setCoordenada(1, tempy);
        this.listaTriangulos[0].getVertice(2).setCoordenada(2, tempz);


        /* Aplicando translação */
        for (int i = 1; i < this.listaTriangulos.length; i++) {
            for (int j = 0; j < 3; j++) {

                boolean rot = true;
                for (int a = 0; a < rotacionados.size(); a++) {

                    if (comparaVertices(this.listaTriangulos[i].getVertice(j), (Vertice) rotacionados.get(a))) {
                        rot = false;

                    }
                }

                if (rot) {

                    tempy = (float) (this.listaTriangulos[i].getVertice(j).getCoordenada(1) * Math.cos(Math.toRadians(rotX))) - (float) (this.listaTriangulos[i].getVertice(j).getCoordenada(2) * Math.sin(Math.toRadians(rotX)));
                    tempz = (float) (this.listaTriangulos[i].getVertice(j).getCoordenada(1) * Math.sin(Math.toRadians(rotX))) + (float) (this.listaTriangulos[i].getVertice(j).getCoordenada(2) * Math.cos(Math.toRadians(rotX)));
                    this.listaTriangulos[i].getVertice(j).setCoordenada(1, tempy);
                    this.listaTriangulos[i].getVertice(j).setCoordenada(2, tempz);
                    rotacionados.add(this.listaTriangulos[i].getVertice(j));
                }
            }
        }

        rotacionados.clear();
    }

    public void rotacionarY(float rotY) {

        Vector rotacionados = new Vector();
        rotacionados.clear();

        float tempx,  tempz;

        /* Adiciona o primeiro triangulo (3 vértices) na lista de Rotacionados */
        rotacionados.add(this.listaTriangulos[0].getVertice(0));
        rotacionados.add(this.listaTriangulos[0].getVertice(1));
        rotacionados.add(this.listaTriangulos[0].getVertice(2));
        /* E também os rotaciona */ //VERTICE 1
        tempz = (float) (this.listaTriangulos[0].getVertice(0).getCoordenada(2) * Math.cos(Math.toRadians(rotY))) - (float) (this.listaTriangulos[0].getVertice(0).getCoordenada(0) * Math.sin(Math.toRadians(rotY)));
        tempx = (float) (this.listaTriangulos[0].getVertice(0).getCoordenada(2) * Math.sin(Math.toRadians(rotY))) + (float) (this.listaTriangulos[0].getVertice(0).getCoordenada(0) * Math.cos(Math.toRadians(rotY)));
        this.listaTriangulos[0].getVertice(0).setCoordenada(0, tempx);
        this.listaTriangulos[0].getVertice(0).setCoordenada(2, tempz);
        // VETICE 2
        tempz = (float) (this.listaTriangulos[0].getVertice(1).getCoordenada(2) * Math.cos(Math.toRadians(rotY))) - (float) (this.listaTriangulos[0].getVertice(1).getCoordenada(0) * Math.sin(Math.toRadians(rotY)));
        tempx = (float) (this.listaTriangulos[0].getVertice(1).getCoordenada(2) * Math.sin(Math.toRadians(rotY))) + (float) (this.listaTriangulos[0].getVertice(1).getCoordenada(0) * Math.cos(Math.toRadians(rotY)));
        this.listaTriangulos[0].getVertice(1).setCoordenada(0, tempx);
        this.listaTriangulos[0].getVertice(1).setCoordenada(2, tempz);
        // VERTICE 3 do Primeiro triangulo
        tempz = (float) (this.listaTriangulos[0].getVertice(2).getCoordenada(2) * Math.cos(Math.toRadians(rotY))) - (float) (this.listaTriangulos[0].getVertice(2).getCoordenada(0) * Math.sin(Math.toRadians(rotY)));
        tempx = (float) (this.listaTriangulos[0].getVertice(2).getCoordenada(2) * Math.sin(Math.toRadians(rotY))) + (float) (this.listaTriangulos[0].getVertice(2).getCoordenada(0) * Math.cos(Math.toRadians(rotY)));
        this.listaTriangulos[0].getVertice(2).setCoordenada(0, tempx);
        this.listaTriangulos[0].getVertice(2).setCoordenada(2, tempz);


        /* Aplicando translação */
        for (int i = 1; i < this.listaTriangulos.length; i++) {
            for (int j = 0; j < 3; j++) {

                boolean rot = true;
                for (int a = 0; a < rotacionados.size(); a++) {

                    if (comparaVertices(this.listaTriangulos[i].getVertice(j), (Vertice) rotacionados.get(a))) {
                        rot = false;

                    }
                }

                if (rot) {
                    tempz = (float) (this.listaTriangulos[i].getVertice(j).getCoordenada(2) * Math.cos(Math.toRadians(rotY))) - (float) (this.listaTriangulos[i].getVertice(j).getCoordenada(0) * Math.sin(Math.toRadians(rotY)));
                    tempx = (float) (this.listaTriangulos[i].getVertice(j).getCoordenada(2) * Math.sin(Math.toRadians(rotY))) + (float) (this.listaTriangulos[i].getVertice(j).getCoordenada(0) * Math.cos(Math.toRadians(rotY)));
                    this.listaTriangulos[i].getVertice(j).setCoordenada(0, tempx);
                    this.listaTriangulos[i].getVertice(j).setCoordenada(2, tempz);
                    rotacionados.add(this.listaTriangulos[i].getVertice(j));
                }
            } // vertices
        } // listaTriangulos

        rotacionados.clear();
    }

    public boolean comparaVertices(Vertice v1, Vertice v2) {

        if ((v1.getCoordenada(0) == v2.getCoordenada(0)) && (v1.getCoordenada(1) == v2.getCoordenada(1)) && (v1.getCoordenada(2) == v2.getCoordenada(2))) {
            return true;
        } else {
            return false;
        }

    }

    public void rotacionarZ(float rotZ) {

        Vector rotacionados = new Vector();
        rotacionados.clear();

        float tempx,  tempy;

        /* Adiciona o primeiro triangulo (3 vértices) na lista de Rotacionados */
        rotacionados.add(this.listaTriangulos[0].getVertice(0));
        rotacionados.add(this.listaTriangulos[0].getVertice(1));
        rotacionados.add(this.listaTriangulos[0].getVertice(2));
        /* E também os rotaciona */ //VERTICE 1
        tempx = (float) (this.listaTriangulos[0].getVertice(0).getCoordenada(0) * Math.cos(Math.toRadians(rotZ))) - (float) (this.listaTriangulos[0].getVertice(0).getCoordenada(1) * Math.sin(Math.toRadians(rotZ)));
        tempy = (float) (this.listaTriangulos[0].getVertice(0).getCoordenada(0) * Math.sin(Math.toRadians(rotZ))) + (float) (this.listaTriangulos[0].getVertice(0).getCoordenada(1) * Math.cos(Math.toRadians(rotZ)));
        this.listaTriangulos[0].getVertice(0).setCoordenada(0, tempx);
        this.listaTriangulos[0].getVertice(0).setCoordenada(1, tempy);
        // VETICE 2
        tempx = (float) (this.listaTriangulos[0].getVertice(1).getCoordenada(0) * Math.cos(Math.toRadians(rotZ))) - (float) (this.listaTriangulos[0].getVertice(1).getCoordenada(1) * Math.sin(Math.toRadians(rotZ)));
        tempy = (float) (this.listaTriangulos[0].getVertice(1).getCoordenada(0) * Math.sin(Math.toRadians(rotZ))) + (float) (this.listaTriangulos[0].getVertice(1).getCoordenada(1) * Math.cos(Math.toRadians(rotZ)));
        this.listaTriangulos[0].getVertice(1).setCoordenada(0, tempx);
        this.listaTriangulos[0].getVertice(1).setCoordenada(1, tempy);
        // VERTICE 3 do Primeiro triangulo
        tempx = (float) (this.listaTriangulos[0].getVertice(2).getCoordenada(0) * Math.cos(Math.toRadians(rotZ))) - (float) (this.listaTriangulos[0].getVertice(2).getCoordenada(1) * Math.sin(Math.toRadians(rotZ)));
        tempy = (float) (this.listaTriangulos[0].getVertice(2).getCoordenada(0) * Math.sin(Math.toRadians(rotZ))) + (float) (this.listaTriangulos[0].getVertice(2).getCoordenada(1) * Math.cos(Math.toRadians(rotZ)));
        this.listaTriangulos[0].getVertice(2).setCoordenada(0, tempx);
        this.listaTriangulos[0].getVertice(2).setCoordenada(1, tempy);


        /* Aplicando translação */
        for (int i = 1; i < this.listaTriangulos.length; i++) {
            for (int j = 0; j < 3; j++) {

                boolean rot = true;
                for (int a = 0; a < rotacionados.size(); a++) {

                    if (comparaVertices(this.listaTriangulos[i].getVertice(j), (Vertice) rotacionados.get(a))) {
                        rot = false;

                    }
                }

                if (rot) {

                    tempx = (float) (this.listaTriangulos[i].getVertice(j).getCoordenada(0) * Math.cos(Math.toRadians(rotZ))) - (float) (this.listaTriangulos[i].getVertice(j).getCoordenada(1) * Math.sin(Math.toRadians(rotZ)));
                    tempy = (float) (this.listaTriangulos[i].getVertice(j).getCoordenada(0) * Math.sin(Math.toRadians(rotZ))) + (float) (this.listaTriangulos[i].getVertice(j).getCoordenada(1) * Math.cos(Math.toRadians(rotZ)));
                    this.listaTriangulos[i].getVertice(j).setCoordenada(0, tempx);
                    this.listaTriangulos[i].getVertice(j).setCoordenada(1, tempy);
                    rotacionados.add(this.listaTriangulos[i].getVertice(j));

                }
            }
        }

        rotacionados.clear();
    }

    public void rotacionar() {

        rotacionarX(rotX);
        rotacionarY(rotY);
        rotacionarZ(rotZ);

    }

    /**
     * Calcula os Máximos e Mínimos em X, Y e Z da Geometria
     * fazendo a varredura na lista de Triangulos vértice a vértice
     */
    public void calculaMaxMin() {

        Triangulo[] t = listaTriangulos;
        float xMaior = Float.MIN_VALUE;
        float yMaior = Float.MIN_VALUE;
        float zMaior = Float.MIN_VALUE;

        float xMenor = Float.MAX_VALUE;
        float yMenor = Float.MAX_VALUE;
        float zMenor = Float.MAX_VALUE;
        Vertice[] v = new Vertice[3];

        /* Varrendo a lista de Triangulos */
        for (int i = 0; i < t.length; i++) {
            v = t[i].getVertice();

            /* Comparando os tres vertices do triangulo i */
            for (int j = 0; j < 3; j++) {
                /* Comparacao para o X */
                if (xMaior < v[j].getCoordenada(0)) {
                    xMaior = v[j].getCoordenada(0);
                } else if (xMenor > v[j].getCoordenada(0)) {
                    xMenor = v[j].getCoordenada(0);
                }

                /* Comparacao para o Y */
                if (yMaior < v[j].getCoordenada(1)) {
                    yMaior = v[j].getCoordenada(1);
                } else if (yMenor > v[j].getCoordenada(1)) {
                    yMenor = v[j].getCoordenada(1);

                }

                /* Comparacao para o Z */
                if (zMaior < v[j].getCoordenada(2)) {
                    zMaior = v[j].getCoordenada(2);
                } else if (zMenor > v[j].getCoordenada(2)) {
                    zMenor = v[j].getCoordenada(2);

                }
            }
        }

        xMax = xMaior;
        yMax = yMaior;
        zMax = zMaior;
        xMin = xMenor;
        yMin = yMenor;
        zMin = zMenor;

    }

    public float getXMax() {
        return xMax;
    }

    public void setXMax(float xMax) {
        this.xMax = xMax;
    }

    public float getXMin() {
        return xMin;
    }

    public void setXMin(float xMin) {
        this.xMin = xMin;
    }

    public float getYMax() {
        return yMax;
    }

    public void setYMax(float yMax) {
        this.yMax = yMax;
    }

    public float getYMin() {
        return yMin;
    }

    public void setYMin(float yMin) {
        this.yMin = yMin;
    }

    public float getZMax() {
        return zMax;
    }

    /**
     * 
     * @param zMax
     */
    public void setZMax(float zMax) {
        this.zMax = zMax;
    }

    /**
     * 
     * @return
     */
    public float getZMin() {
        return zMin;
    }

    /**
     * 
     * @param zMin
     */
    public void setZMin(float zMin) {
        this.zMin = zMin;
    }

    /**
     * 
     * @return
     */
    public boolean isVisible() {
        if (visivel == true) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * 
     * @return
     */
    public boolean isSolid() {
        if (solido == true) {
            return true;
        } else {
            return false;
        }
    }

    public void setVisible(boolean status) {
        this.visivel = status;
    }

    public void setSolid(boolean status) {
        this.solido = status;
    }

    public Color getColor() {
        return material.getCor();
    }

    @Override
    public String toString() {
        return nome;
    }

    public float getRotX() {
        return rotX;
    }

    public void setRotX(float rotX) {
        this.rotX = rotX;
    }

    public float getRotY() {
        return rotY;
    }

    public void setRotY(float rotY) {
        this.rotY = rotY;
    }

    public float getRotZ() {
        return rotZ;
    }

    public void setRotZ(float rotZ) {
        this.rotZ = rotZ;
    }
    
    public float getTransX() {
        return transX;
    }

    public void setTransX(float v) {
        this.transX = v;
    }

    public float getTransY() {
        return transY;
    }

    public void setTransY(float v) {
        this.transY = v;
    }

    public float getTransZ() {
        return transZ;
    }

    public void setTransZ(float v) {
        this.transZ = v;
    }
}
